import { CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer";
import { App } from "../../application";
import Events from "../../application/constants/Events";
import { Vector3 } from "three";
import { GeoUtils, Point } from "../../Engine";
import PoiCollisionManager from "../../map/utils/PoiCollisionManager";
import AdjustHeight from "./utils/AdjustHeight";

/**
 * HMTL标记对象
 */
export default class HtmlMarker extends CSS2DObject {
    private app: App;
    private isOpenCollision: boolean;
    private falldownSurface: boolean;
    private adjustHeightUtil;

    /**
     * 构造函数
     * @param element domElement
     * @param options 配置项
     * @param options.position 标记位置，如果不设置就默认为0,0点，也可以创建后手动设置position
     * @param options.isCollisionCheck 该marker是否做碰撞检测
     * @example let div = document.createElement('div');
     div.className = 'label';
     div.textContent = 'HTML标记1';
     div.style.backgroundColor = 'transparent'; 
     const button = document.createElement('button');
     button.innerText = '按钮1';
     button.style.width = '80px';
     button.style.height = '30px';
     button.onclick = function (e) {
         alert('1号按钮点击'); 
     }
     div.appendChild(button);
     //初始化标注组件，并将htmlelement作为参数传入，这里是一个div
     let label = new GE.HtmlMarker(div);
     //设置组件在三维场景中的位置
     let position = new GE.Point(119.69329835650711, 30.55561178489569, 0, '4326').toEPSGWeb();
     label.position.set(position.x, position.y, 0);
     //设置对其方式，0,0为中心对齐
     label.center.set(0, 0);
     //将组件添加至场景中
     app.add(label);
     */
    public constructor(element: HTMLElement, options?: { position: Point, isCollisionCheck:boolean, falldownSurface?: boolean}) {
        super(element);
       
        this.app = App.getInstance();

        if (options) {
            if(options.position){
                options.position.toEPSGWeb();
                this.position.copy(options.position);
            }
            
            if(options.isCollisionCheck == true){ //该marker做碰撞检测，透明度先设为0，在碰撞检测中判断是否把透明度设为1
                this.element.style.opacity = '0.0';
            }else{
               this.occlusionCheckFog();
            }

            if(options.falldownSurface){
                this.setFalldown();
            }
        }else{
            this.occlusionCheckFog();
        }
    }

    /**
     * 开启碰撞检测。该方法需要在设置了marker的position之后调用，否则无效。另外先调用该方法的marker在碰撞中的优先级比较低，后调用该方法的marker在碰撞中的优先级比较高
     * @param tileJson 该marker的瓦片信息，可以不传，因为该方法内部会计算瓦片号。但是如果有多个marker堆积在一起，最好传瓦片信息，以提高性能。该参数的格式：{x: number, y: number, z: number}
     */
    public openCollisionCheck(tileJson?){
        if(!tileJson){ //如果没有瓦片信息，就根据marker的位置来计算瓦片信息
            let zoom = this.app.map.zoom;
            let col = GeoUtils.getC10(this.position.x, zoom);
            let row = GeoUtils.getR10(this.position.y, zoom);
            tileJson = {x: col, y: row, z: zoom};
        }

        let tileStr = JSON.stringify(tileJson);
        let tempTile = PoiCollisionManager.getTile(tileStr);
        if(tempTile){
            tileJson = tempTile;
        }

        let isSuccess = PoiCollisionManager.addPoiTile(tileJson, this);
        if(!isSuccess){
            this.dispose();
        }else{
            this.isOpenCollision = true;
        }
    }

    private disposeCount:number = 0;
    public dispose(){
        let parent = this.parent;
            if(parent){
                parent.remove(this);
            }else{
                this.disposeCount++;
                if(this.disposeCount >= 10){
                    return;
                }

                let self = this;
                setTimeout(() => {
                    self.dispose();
                }, 10);
            }
    }

    private occlusionCheckFog(){
        if (this.app.background.fog) { //该marker不做碰撞检测，但是要防止该marker出现在雾中
            this.app.on(Events.CameraChange, this.setMarkerVisible.bind(this));
            this.setMarkerVisible();
        }
    }

    public setMarkerVisible() { //在检查是否被雾遮挡的时候用到该方法
        if (!this.app.background.fog) {
            return;
        }

        let cameraPosition: Vector3 = this.app.three.camera.position;
        let worldPosition = this.getWorldPosition(new Vector3());
        let distance = cameraPosition.distanceTo(worldPosition) * 0.7;
        if (distance >= this.app.background.fog.near) {
            this.element.style.opacity = '0.0'; //可以用这个属性解决label被雾遮挡的问题
            this.element.style['fogCover'] = true;
        } 
        else {
            this.element.style['fogCover'] = false;
            if(!this.isOpenCollision){
                this.element.style.opacity = '1.0'; //这里这样做是为了避免在碰撞检测中出现闪动的问题
            }
            
        }
    }

    public isCoveredByFog(){
        if (!this.app.background.fog) {
            return false;
        }

        let cameraPosition: Vector3 = this.app.three.camera.position;
         let worldPosition = this.getWorldPosition(new Vector3());
        let distance = cameraPosition.distanceTo(worldPosition) * 0.7;
        if (distance >= this.app.background.fog.near) {
            this.element.style.opacity = '0.0'; //可以用这个属性解决label被雾遮挡的问题
            return true;
        } 

        return false;
    }

    
    private setFalldown() {
        let adjustHeightData = {mesh: this, falldownSurface: this.falldownSurface};
        this.adjustHeightUtil = new AdjustHeight(adjustHeightData);
        this.adjustHeightUtil.startAdjust();
    }
}